#include "stdafx.h"
#include <wx/choice.h>
#include "wxhelper.h"
#include <wx/msw/ole/automtn.h>
#include <wx/msw/ole/access.h>
#include <wx/msw/ole/oleutils.h>
#include "wx/window.h"
#include "wx/log.h"
#include <wx/msw/ole/safearray.h>






int wxFillChoice(wxChoice * pwnd,ado::ConnectionPtr con,const wchar_t* sql,
                      const wchar_t* key,const wchar_t * value,int defSel)
{
    if(key==NULL)
        key=L"KEY";
    if(value==NULL)
        value=L"VALUE";
    int nr=0;
    try {
        ado::RecordsetPtr rs=con->Execute(_bstr_t(sql),NULL,ADODB::adOptionUnspecified);
        while(!rs->GetadoEOF())
        {
            int nn=pwnd->Append((const wchar_t*)_bstr_t(rs->GetCollect(key)));
            pwnd->SetClientObject(nn,new TClientData<std::wstring>((const wchar_t*)_bstr_t(rs->GetCollect(value))));
            rs->MoveNext();
        }
        rs->Close();
        rs.Release();
    } catch (_com_error & e) {
        ado::ShowError(e);
    }
    if(defSel>=0)
    {
        int nc=pwnd->GetCount();
        if(nc>0)
        {
            if(defSel>=nc)
            {
                defSel=nc-1;
            }
            pwnd->Select(defSel);
        }
    }
    return nr;
}
int wxFillChoice2(wxChoice * pwnd,ado::ConnectionPtr  con,const wchar_t * sql,
                      const wchar_t* key,const wchar_t * value,const wchar_t* defVAl)
{
    if(key==NULL)
        key=L"KEY";
    if(value==NULL)
        value=L"VALUE";
    int nr=0;
    try {
        ado::RecordsetPtr rs=con->Execute(_bstr_t(sql),NULL,ADODB::adOptionUnspecified);
        while(!rs->GetadoEOF())
        {
            int nn=pwnd->Append((const wchar_t*)_bstr_t(rs->GetCollect(key)));
            pwnd->SetClientObject(nn,new TClientData<std::wstring>((const wchar_t*)_bstr_t(rs->GetCollect(value))));
            rs->MoveNext();
        }
        rs->Close();
        rs.Release();
    } catch (_com_error & e) {
        ado::ShowError(e);
    }
    if(defVAl)
    {
        int nc=pwnd->GetCount();
        if(nc>0)
        {
            int defSel=pwnd->FindString(defVAl);
            if(defSel>=0)
                pwnd->Select(defSel);
        }
    }
    return nr;
}

static double GetVariantDec(const VARIANTARG *pvargDest )
{
    _variant_t vs=*pvargDest;
    _variant_t va;
    HRESULT hr=VariantChangeType(&va,
      &vs,
       VARIANT_ALPHABOOL,
      VT_R8
    );
    if(FAILED(hr))
    {
        return 0.0;
    }else
    {
        return (double)va;
    }
}

bool myConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant, long flags)
{

    bool ok = true;
    if ( oleVariant.vt & VT_ARRAY )
    {
        if ( flags & wxOleConvertVariant_ReturnSafeArrays  )
        {
            variant.SetData(new wxVariantDataSafeArray(oleVariant.parray));
        }
        else
        {
            switch (oleVariant.vt & VT_TYPEMASK)
            {
                case VT_I2:
                    ok = wxSafeArray<VT_I2>::ConvertToVariant(oleVariant.parray, variant);
                    break;
                case VT_I4:
                    ok = wxSafeArray<VT_I4>::ConvertToVariant(oleVariant.parray, variant);
                    break;
                case VT_R4:
                    ok = wxSafeArray<VT_R4>::ConvertToVariant(oleVariant.parray, variant);
                    break;
                case VT_R8:
                    ok = wxSafeArray<VT_R8>::ConvertToVariant(oleVariant.parray, variant);
                    break;
                case VT_VARIANT:
                    ok = wxSafeArray<VT_VARIANT>::ConvertToVariant(oleVariant.parray, variant);
                    break;
                case VT_BSTR:
                    {
                        wxArrayString strings;
                        if ( wxSafeArray<VT_BSTR>::ConvertToArrayString(oleVariant.parray, strings) )
                            variant = strings;
                        else
                            ok = false;
                    }
                    break;
                default:
                    ok = false;
                    break;
            }
            if ( !ok )
            {
                wxLogDebug(wxT("unhandled VT_ARRAY type %x in myConvertOleToVariant"),
                           oleVariant.vt & VT_TYPEMASK);
                variant = wxVariant();
            }
        }
    }
    else if ( oleVariant.vt & VT_BYREF )
    {
        switch ( oleVariant.vt & VT_TYPEMASK )
        {
            case VT_VARIANT:
                {
                    VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref);
                    if (!myConvertOleToVariant(oleReference,variant))
                        return false;
                    break;
                }

            default:
                wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),
                            oleVariant.vt);
                return false;
        }
    }
    else // simply type (not array or reference)
    {
        switch ( oleVariant.vt & VT_TYPEMASK )
        {
            case VT_ERROR:
                variant.SetData(new wxVariantDataErrorCode(oleVariant.scode));
                break;

            case VT_CY:
                variant.SetData(new wxVariantDataCurrency(oleVariant.cyVal));
                break;

            case VT_BSTR:
                {
                    wxString str(wxConvertStringFromOle(oleVariant.bstrVal));
                    variant = str;
                }
                break;

            case VT_DATE:
#if wxUSE_DATETIME
                {
                    SYSTEMTIME st;
                    VariantTimeToSystemTime(oleVariant.date, &st);

                    wxDateTime date;
                    date.SetFromMSWSysTime(st);
                    variant = date;
                }
#endif // wxUSE_DATETIME
                break;

#if wxUSE_LONGLONG
            case VT_I8:
                variant = wxLongLong(oleVariant.llVal);
                break;
#endif // wxUSE_LONGLONG

            case VT_I4:
                variant = (long) oleVariant.lVal;
                break;

            case VT_I2:
                variant = (long) oleVariant.iVal;
                break;

            case VT_BOOL:
                variant = oleVariant.boolVal != 0;
                break;

            case VT_R4:
                variant = oleVariant.fltVal;
                break;

            case VT_R8:
                variant = oleVariant.dblVal;
                break;
            case VT_DECIMAL:
                variant=GetVariantDec(&oleVariant);
                break;
            case VT_DISPATCH:
                variant = (void*) oleVariant.pdispVal;
                break;

            case VT_NULL:
            case VT_EMPTY:
                variant.MakeNull();
                break;

            default:
                wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),
                           oleVariant.vt,oleVariant.vt&VT_TYPEMASK);
                return false;
        }
    }

    return ok;
}






wxTable::wxTable()
    :m_keymap(new wxTable::StringIndexMap),m_data(new wxTable::Table)
{

}

wxTable::~wxTable()
{

}

void wxTable::Clear()
{
    this->m_keymap->clear();
    this->m_data->clear();
}

void wxTable::FillData(ado::ConnectionPtr con, const wchar_t *sql)
{
    Clear();

    try {
        ado::RecordsetPtr rs=con->Execute(_bstr_t(sql),NULL,ADODB::adOptionUnspecified);
        {
            ado::FieldsPtr fields=rs->GetFields();
            long nc=fields->GetCount();
            for(long i=0;i<nc;++i)
            {
                ado::FieldPtr field=fields->GetItem(_variant_t(i));
                typedef wxTable::StringIndexMap::value_type si_pair;
                m_keymap->insert(si_pair((const wchar_t*)field->GetName(),i));
            }
        }

        if(!rs->GetadoEOF())
        {
            long nc=m_keymap->size();
            do{

                ado::FieldsPtr fields=rs->GetFields();
                wxTable::RowDataPtr row=NewRowData(nc);
                for(long i=0;i<nc;++i)
                {
                    ado::FieldPtr field=fields->GetItem(_variant_t(i));

                    row.get()[i]=field->GetValue();

                }
                this->m_data->push_back(row);
                rs->MoveNext();
            }while(rs->GetadoEOF());
        }
    } catch (_com_error & e) {

        ado::ShowError(e);
    }

}

void wxTable::FillData(ado::ConnectionPtr con, const wchar_t *sql, std::function<bool (wxTable::Row::RowPtr &)> cbf)
{
    Clear();

    try {
        ado::RecordsetPtr rs=con->Execute(_bstr_t(sql),NULL,ADODB::adOptionUnspecified);
        {
            ado::FieldsPtr fields=rs->GetFields();
            long nc=fields->GetCount();
            for(long i=0;i<nc;++i)
            {
                ado::FieldPtr field=fields->GetItem(_variant_t(i));
                typedef wxTable::StringIndexMap::value_type si_pair;
                m_keymap->insert(si_pair((const wchar_t*)field->GetName(),i));
            }
        }

        if(!rs->GetadoEOF())
        {
            long nc=m_keymap->size();
            long row_idx=0;
            do{

                ado::FieldsPtr fields=rs->GetFields();
                wxTable::RowDataPtr rowdata=NewRowData(nc);
                for(long i=0;i<nc;++i)
                {
                    ado::FieldPtr field=fields->GetItem(_variant_t(i));

                    rowdata.get()[i]=field->GetValue();

                }
                wxTable::Row::RowPtr row=wxTable::Row::New(row_idx,m_keymap,rowdata);
                if(cbf(row))
                {
                    this->m_data->push_back(rowdata);
                    row_idx+=1;
                }
                rs->MoveNext();
            }while(!rs->GetadoEOF());
        }
    } catch (_com_error & e) {

        ado::ShowError(e);
    }
}
